//
// Created by 吴喆 on 2020/3/3.
//

#ifndef SUMMER_INPUT_H
#define SUMMER_INPUT_H

#include <glad/glad.h>
#include <GLFW/glfw3.h>

#include <utility>
#include <glm/glm.hpp>
#include <unordered_map>
#include <list>

//enum class EVENT_TYPE {
//    MOUSE_CLICK, KEYBOARD_CLICK, CURSOR_MOVE
//};
class KeyEvent {
public:
    KeyEvent(int key, int scanCode, int action, int mods)
            : key(key), action(action), mods(mods) {
        if (action == GLFW_PRESS) {
            down = true;
            released = false;
            held = true;
        }
        if (action == GLFW_REPEAT) {
            down = false;
            released = false;
            held = true;
        }
        if (action == GLFW_RELEASE) {
            down = false;
            released = true;
            held = false;
        }
    }

    int key;
    int action;
    int mods;

    bool held = false;
    bool down = false;
    bool released = false;
};

class MouseEvent {
public:
    MouseEvent(int button, int action, int mods) : button(button), action(action), mods(mods) {
        if (action == GLFW_PRESS) {
            down = true;
            up = false;
            held = true;
        }
        if (action == GLFW_RELEASE) {
            down = false;
            up = true;
            held = false;
        }
    }

    int button;
    int action;
    int mods;
    bool down;
    bool up;
    bool held;
};

class MouseObserver {

public:
    virtual void onMouseBtnInput(MouseEvent *) {};

    virtual void onCursorMove(double x, double y) {};
};

class KeyboardObserver {

public:
    virtual void onKeyboardInput(KeyEvent *) {};
};

/**
 * 用于对键盘鼠标输入的控制
 */
class Input {
public:

    static Input *getInstance() {
        return input;
    }

    std::unordered_map<int, KeyEvent *> keyMap;
    std::unordered_map<int, MouseEvent *> mouseMap;

    void initCallback(GLFWwindow *win, std::pair<int, int> pos);

    // 返回鼠标位置
    glm::vec2 getMousePos();


    // 键盘回调函数
    void keyCallback(GLFWwindow *window, int key, int scancode, int action, int mods);

    // 鼠标点击回调函数
    void mouseClickCallback(GLFWwindow *window, int button, int action, int mods);

    // 鼠标
    void cursorCallback(GLFWwindow *window, double posX, double posY);


    //添加观察者
    void attach2MouseClick(MouseObserver *observer) {
        mouseClickObservers.push_back(observer);
    }

    //添加观察者
    void attach2KeyboardClick(KeyboardObserver *observer) {
        keyboardObservers.push_back(observer);
    }

    //添加观察者
    void attach2CursorMove(MouseObserver *observer) {
        cursorMoveObservers.push_back(observer);
    }


private:
    Input() = default;

    static Input *input;
    GLfloat posX = 0.0f;
    GLfloat posY = 0.0f;
    std::list<MouseObserver *> mouseClickObservers;
    std::list<KeyboardObserver *> keyboardObservers;
    std::list<MouseObserver *> cursorMoveObservers;

    void notifyMouseClick(MouseEvent *event) {
        for (auto observer : mouseClickObservers) {
            observer->onMouseBtnInput(event);
        }
    }

    void notifyKeyboardClick(KeyEvent *event) {
        for (auto observer : keyboardObservers) {
            observer->onKeyboardInput(event);
        }
    }
    void notifyCursorMove(double x, double y) {
        for (auto observer : cursorMoveObservers) {
            observer->onCursorMove(x, y);
        }

    }
};


#endif //SUMMER_INPUT_H
